package com.bes.sdk.core;


import static com.bes.bessdk.service.BesOTAConstants.OTA_SEND_DATA_PROGRESS;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.bes.bessdk.BesSdkConstants;
import com.bes.bessdk.service.BesOtaService;
import com.bes.bessdk.service.base.BesServiceConfig;
import com.bes.bessdk.service.base.BesServiceListener;
import com.bes.bessdk.service.customerdial.CustomerDialConstants;
import com.bes.bessdk.service.customerdial.CustomerDialService;
import com.bes.bessdk.utils.LogUtils;
import com.bes.sdk.device.HmDevice;
import com.bes.sdk.ota.OTADfuInfo;
import com.bes.sdk.ota.OTATask;
import com.bes.sdk.ota.RemoteOTAConfig;
import com.bes.sdk.utils.DeviceProtocol;
import com.bes.sdk.utils.OTAStatus;

import java.util.LinkedList;

public class BesOtaManager {
    public final String TAG = "BesOtaManager";
    private boolean isRelease = true;
    private boolean isOtaResFinish = false;
    private boolean isOtaing = false;
    //已经OTA完成的大小
    private float completedSize;
    //全部OTA文件的大小
    private float totalSize;
    //当前bin文件大小
    private float currentBinSize;
    private int lastProgress = 0;
    private byte[] otaData = new byte[0];
    private String mac;
    private static volatile BesOtaManager instance = null;
    private LinkedList<BesOtaEntity.OtaItem> otaItems =new LinkedList<>();
    private BesOtaEntity.OtaItem currentOta;
    private BesOtaEntity.OtaItem otaFw;  //固件包
    private BesOtaCallback besOtaCallback;
    private Context context;
    private CustomerDialService dialService;
    private BesOtaService fwService;
    private final Handler handler = new Handler(Looper.getMainLooper());

    private BesOtaManager() {
    }

    public static BesOtaManager getInstance() {
        if (instance == null) {
            synchronized (BesOtaManager.class) {
                if (instance == null) {
                    instance = new BesOtaManager();
                }
            }
        }
        return instance;
    }

    public void startUpgrade(Context context, String mac, BesOtaEntity besOtaEntity, BesOtaCallback otaCallback) {
        this.context = context;
        OtaLog.logI("OTA mac " + mac);
        if(isOtaing){
            loge("OTA ing, Disallow repeat call");
            return;
        }
        StringBuilder sb = new StringBuilder();
        if (besOtaEntity.otaDataList.isEmpty() || TextUtils.isEmpty(mac)) {
            OtaLog.logI("OTA data is nil or mac address is nil");
            otaCallback.onFailure(-1, new Throwable("param error"));
            return;
        }
        isOtaing = true;
        isOtaResFinish = false;
        isRelease = false;
        totalSize = 0;
        completedSize = 0;
        currentBinSize = 0;
        besOtaCallback = otaCallback;
        otaItems.clear();
        this.mac = mac;
        for (int i = 0; i < besOtaEntity.otaDataList.size(); i++) {
            BesOtaEntity.OtaItem otaItem = besOtaEntity.otaDataList.get(i);
            totalSize += otaItem.bytes.length;
            sb.append(otaItem);
            if (otaItem.type == BesOtaEntity.OtaItem.TYPE_FW) {
                otaFw = otaItem;
            } else {
                otaItems.add(otaItem);
            }
        }
        int kb = (int) (totalSize / 1024f);
        OtaLog.logI("OTA 总大小" + kb + "(kb) list " + sb);
        if (OtaLog.isWriteFile) {
            LogUtils.writeLog(TAG, "initialize 总大小 " + kb + "kb");
        }
        besOtaCallback.initialize();
        if (otaItems.isEmpty() && otaFw != null) {
            isOtaResFinish = true;
            startConnectFwService();
        } else {
            //有资源
            startConnectResService();
        }
    }

    public void interruptUpgrade() {
        release("interruptUpgrade");
    }

    private void log(String log){
        OtaLog.logI(log);
    }

    private void loge(String log){
        OtaLog.logE(log);
    }

    private void startConnectResService() {
        BesServiceConfig customerDialConfig = new BesServiceConfig();
        customerDialConfig.setServiceUUID(BesSdkConstants.BES_SPP_CONNECT);
        customerDialConfig.setUseTotaV2(true);
        customerDialConfig.setTotaConnect(true);
        customerDialConfig.setDeviceProtocol(DeviceProtocol.PROTOCOL_SPP);
        HmDevice hmDevice = new HmDevice();
        hmDevice.setDeviceMAC(mac);
        hmDevice.setPreferredProtocol(DeviceProtocol.PROTOCOL_SPP);
        customerDialConfig.setDevice(hmDevice);
        log("创建资源服务: " + mac);
        dialService = new CustomerDialService(customerDialConfig, customerDialListener, context);
    }

    private void startRes() {
        if (isRelease) {
            loge("startRes isRelease");
            return;
        }
        if (otaItems.isEmpty()) {
            log("OTA 资源完成了 ");
            isOtaResFinish = true;
            //OTA 资源完成了
            if (dialService != null) {
                log("OTA 资源服务断开 ");
                dialService.disconnected();
            }
            log("OTA 固件服务延迟2秒启动 ");
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (isRelease) {
                        return;
                    }
                    startConnectFwService();
                }
            }, 2000);
            return;
        }

        currentOta = otaItems.getFirst();
        log("开始OTA资源：" + currentOta);
        currentBinSize = currentOta.bytes.length;
        dialService.startTransfer(null, currentOta.bytes, currentOta.type, 0, currentOta.param);
    }

    private final BesServiceListener customerDialListener = new BesServiceListener() {
        @Override
        public void onTotaConnectState(boolean state, HmDevice hmDevice) {
            log("customerDialListener-onTotaConnectState "+state);
            if (state) {
                startRes();
            } else {
                //判断是否资源全部升级完，否则就是OTA中断了
            }
        }

        @Override
        public void onErrorMessage(int msg, HmDevice hmDevice) {
            loge("customerDialListener onErrorMessage " + msg);
            // customerDialListener onErrorMessage 444
            if (!isOtaResFinish && dialService != null) {
                if (besOtaCallback != null) {
                    if (OtaLog.isWriteFile) {
                        LogUtils.writeLog(TAG, "OTA资源报错" + msg);
                    }
                    besOtaCallback.onFailure(msg, new Throwable("OTA资源报错:错误码0x" + Integer.toHexString(msg)));
                }
                release("customerDialListener onErrorMessage");
            }
        }

        @Override
        public void onStateChangedMessage(int msg, String msgStr, HmDevice hmDevice) {
            if (isRelease) {
                loge("customerDialListener onStateChangedMessage isRelease msg" + msg);
                return;
            }
            if (msg == CustomerDialConstants.OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT_OK) {
                if (currentOta != null) {
                    completedSize += currentOta.bytes.length;
                    log("OTA：" + currentOta.type + " 成功,completedSize:" + completedSize);
                    otaItems.remove(currentOta);
                }
                startRes();
            } else if (msg == BesSdkConstants.BES_CONNECT_ERROR) {
                onErrorMessage(msg, hmDevice);
            } else if (msg == CustomerDialConstants.OP_TOTA_WRITE_FLASH_PROCESS) {
                log("res onOTAProgressChanged " + msgStr);
                try {
                    callProgressChange(Float.parseFloat(msgStr));
                } catch (NumberFormatException e) {
                }
            }
        }

        @Override
        public void onSuccessMessage(int msg, HmDevice hmDevice) {
            log("customerDialListener onSuccessMessage " + msg);
        }
    };

    //⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️3.connect Device
    public void startConnectFwService(Context context, String mac, byte[] data, BesOtaCallback otaCallback) {
        if(isOtaing){
            loge("OTA ing, Disallow repeat call");
            return;
        }
        isOtaing = true;
        isOtaResFinish = false;
        isRelease = false;
        totalSize = 0;
        completedSize = 0;
        currentBinSize = 0;
        this.context = context;
        besOtaCallback = otaCallback;
        otaData = data;

        //⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️4.Set parameters based on the specific function
        BesServiceConfig serviceConfig = new BesServiceConfig();
        HmDevice hmDevice = new HmDevice();
        hmDevice.setBleAddress(mac);
        serviceConfig.setDevice(hmDevice);
        serviceConfig.setDeviceProtocol(DeviceProtocol.PROTOCOL_BLE);
        serviceConfig.setServiceUUID(BesSdkConstants.BES_OTA_SERVICE_OTA_UUID);
        serviceConfig.setCharacteristicsUUID(BesSdkConstants.BES_OTA_CHARACTERISTIC_OTA_UUID);
        serviceConfig.setDescriptorUUID(BesSdkConstants.BES_OTA_DESCRIPTOR_OTA_UUID);
        serviceConfig.setUSER_FLAG(1);

        fwService = new BesOtaService(serviceConfig, fwListener, context);
    }

    private void startConnectFwService() {
        if (isRelease) {
            loge("startConnectFwService  isRelease");
            return;
        }
        if (otaFw == null) {
            //没有固件包，直接成功
            log("OTA 固件没有找到固件包直接成功 ");
            if (besOtaCallback != null) {
                besOtaCallback.onSuccess();
                if (OtaLog.isWriteFile) {
                    LogUtils.writeLog(TAG, "besOtaCallback.onSuccess()");
                }
            }
            release("startConnectFwService otaFw is null");
        } else {
            BesServiceConfig serviceConfig = new BesServiceConfig();
            HmDevice hmDevice = new HmDevice();
            hmDevice.setDeviceMAC(mac);
            serviceConfig.setDevice(hmDevice);
            serviceConfig.setDeviceProtocol(DeviceProtocol.PROTOCOL_SPP);
            serviceConfig.setServiceUUID(BesSdkConstants.BES_OTA_SERVICE_OTA_UUID);
            serviceConfig.setUSER_FLAG(1);
//            serviceConfig.setCharacteristicsUUID(mServiceConfig.getCharacteristicsUUID());
//            serviceConfig.setDescriptorUUID(mServiceConfig.getDescriptorUUID());
//            serviceConfig.setTotaConnect(mServiceConfig.getTotaConnect());
//            serviceConfig.setUseTotaV2(mServiceConfig.getUseTotaV2());
//            serviceConfig.setUSER_FLAG(mServiceConfig.getUSER_FLAG());
//            serviceConfig.setCurUser(mServiceConfig.getCurUser());
//            serviceConfig.setCurUpgateType(mServiceConfig.getCurUpgateType());
//            serviceConfig.setCurAckType(mServiceConfig.getCurAckType());
//            serviceConfig.setImageSideSelection(mServiceConfig.getImageSideSelection());
//            serviceConfig.setIsWithoutResponse(mServiceConfig.getIsWithoutResponse());
            log("创建OTA固件服务 ");
            fwService = new BesOtaService(serviceConfig, fwListener, context);
        }
    }

    private void startOtaFw() {
        if (isRelease) {
            loge("startOtaFw isRelease");
            return;
        }
        RemoteOTAConfig config = new RemoteOTAConfig();
        config.setLocalBytes(otaData);
        currentBinSize = otaData.length;
        fwService.setOtaConfig(config);
        OTADfuInfo otaDfuInfo = new OTADfuInfo("001", 0);
        log("开始OTA固件 startDataTransfer " + config);
        fwService.startDataTransfer(otaDfuInfo, new OTATask.StatusListener() {
            @Override
            public void onOTAStatusChanged(OTAStatus newStatus, HmDevice hmDevice) {
                log("OTA固件 onOTAStatusChanged " + newStatus);
                //OTA固件 onOTAStatusChanged STATUS_FAILED
            }

            @Override
            public void onOTAProgressChanged(int progress, HmDevice hmDevice) {
//                log("OTA固件 onOTAProgressChanged " + progress);
                callProgressChange(progress);

            }
        });
    }

    private void callProgressChange(float progress) {
        float per = progress / 100 * currentBinSize;
        int totalProgress = (int) ((completedSize + per) / totalSize * 1000);
        if (lastProgress == totalProgress) return;
        lastProgress = totalProgress;
        if (besOtaCallback != null) {
            besOtaCallback.onProgress(totalProgress / 10f);
        }
    }

    private final BesServiceListener fwListener = new BesServiceListener() {
        @Override
        public void onTotaConnectState(boolean state, HmDevice hmDevice) {
            log("fwListener onTotaConnectState " + state);
        }
        @Override
        public void onErrorMessage(int msg, HmDevice hmDevice) {
            loge("fwListener onErrorMessage " + msg);
            if (besOtaCallback != null) {
                besOtaCallback.onFailure(msg, new Throwable("OTA固件报错:错误码0x" + Integer.toHexString(msg)));
            }
            if (OtaLog.isWriteFile) {
                LogUtils.writeLog(TAG, "OTA固件报错 0x" +  Integer.toHexString(msg));
            }
            if (fwService != null) {
                release("fwListener onErrorMessage ");
            }
        }
        @Override
        public void onStateChangedMessage(int msg, String msgStr, HmDevice hmDevice) {
            if (msg == BesSdkConstants.BES_CONNECT_SUCCESS) {
                log("OTA固件服务连接成功 " + msgStr);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        startOtaFw();
                    }
                },2000);

            } else if (msg == OTA_SEND_DATA_PROGRESS) {

            } else if (msg == 444) {
                onErrorMessage(msg, hmDevice);
            }  else {
                //fw onStateChangedMessage 2336 11.97
                log("fw onStateChangedMessage 0x" + Integer.toHexString(msg) + "  " + msgStr);
            }
        }

        @Override
        public void onSuccessMessage(int msg, HmDevice hmDevice) {
            log("fwListener onSuccessMessage " + msg);
            if (besOtaCallback != null) {
                besOtaCallback.onSuccess();
                if (OtaLog.isWriteFile) {
                    LogUtils.writeLog(TAG, "回调 onSuccess " );
                }
            }
            if (fwService != null) {
                fwService.stopDataTransfer();
                fwService.disconnected();
                fwService = null;
            }
            release("fwListener onSuccessMessage");
        }
    };

    /*
    1. connectCustomerDialDevice

 2.  等那个事件表面连接成功？
 onStateChangedMessage里的BES_CONNECT_SUCCESS
如果是TOTA,可以看onTotaConnectState方法


  3.调用  startCustomerDialTransfer
  4. onStateChangedMessage  OP_TOTA_WRITE_FLASH_PROCESS 回调进度

  5. onStateChangedMessage  OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT_OK 回调升级成功

  6.判断是否还有资源要升级，如果没有，直接调用disconnectCustomerDialService

  7. 这里要判断断连成功的回调吗？还是直接执行8
可以延时1s就执行8

 8.调用connectDevice

 9.那个事件表面连接成功，可以开始调用startOta?
1）资源文件由于是TOTA，在onTotaConnectState方法
2）OTA的话onStateChangedMessage里的 BES_CONNECT_SUCCES
 10.调用startOta
 11 那个事件是回调OTA固件的进度？z
 onOTAProgressChanged
 12 那个事件表面是OTA固件成功的标识？
OTA_CMD_WHOLE_CRC_CHECK_OK
 13.调用 什么函数释放全部资源，并断开SPP等？


     */

    public void release(String tag) {
        log("BesOtaManager release:" + tag);
        completedSize = 0;
        currentBinSize = 0;
        totalSize = 0;
        isOtaing = false;
        isRelease = true;
        isOtaResFinish = false;
        context = null;
        besOtaCallback = null;
        otaItems.clear();
        if (dialService != null) {
            dialService.disconnected();
        }
        if (fwService != null) {
            fwService.stopDataTransfer();
            fwService.disconnected();
        }
        dialService = null;
        fwService = null;
    }
}
